import { Graph, Node } from "@antv/x6";
import { CellType } from "../enums";
import { MonitorBoardConfig, NodeConfig, PiplineConifg, RgvConfig, ScenarioConfig, SiteNodeConfig, SrmConfig } from "../models";
import { MonitorBoardNode } from "./MonitorBoardNode";
import { PiplineNode } from "./PiplineNode";
import { RgvNode } from "./RgvNode";
import { SiteNode } from "./SiteNode";
import { SrmNode } from "./SrmNode";

export const Constance = {
  sizes: {
    srm: { width: 500, height: 80 },
    pipline: { width: 500, height: 400 },
    site: { width: 100, height: 100 },
    monitorBoard: { width: 400, height: 400 },
  }
};

export function registerTypes() {
  PiplineNode.register();
  SiteNode.register();
  SrmNode.register();
  MonitorBoardNode.register();
  RgvNode.register();
}

export function unregisterTypes() {
  PiplineNode.unregister();
  SiteNode.unregister();
  SrmNode.unregister();
  MonitorBoardNode.unregister();
  RgvNode.unregister();
}

export function getMetaFromType(type: CellType): Node.Metadata {
  switch (type) {
    case CellType.Pipline:
      return PiplineNode.getMeta();
    case CellType.Site:
      return SiteNode.getMeta();
    case CellType.Srm:
      return SrmNode.getMeta();
    case CellType.MonitorBoard:
      return MonitorBoardNode.getMeta();
    case CellType.Rgv:
      return RgvNode.getMeta();
    default:
      throw new Error("Unknown type");
  }
}

export function updateScenarioNode(cfg: NodeConfig, node: Node) {
  if (node instanceof SrmNode) {
    node.update(cfg as SrmConfig);
  } else if (node instanceof SiteNode) {
    node.update(cfg as SiteNodeConfig);
  } else if (node instanceof PiplineNode) {
    node.update(cfg as PiplineConifg);
  } else if (node instanceof MonitorBoardNode) {
    node.update(cfg as MonitorBoardConfig);
  } else if (node instanceof RgvNode) {
    node.update(cfg as RgvConfig);
  }
}

export function getPiplines(nodes: Node[]): PiplineConifg[] {
  const piplines = nodes.filter((node) => node instanceof PiplineNode).map(node => <PiplineNode>node);
  return piplines.map(pipline => {
    const cfg = pipline.getConfig();
    cfg.Sites = nodes.filter(node => node instanceof SiteNode && node.getParentId() == pipline.id).map(a => <SiteNode>a)
      .map(site => site.getConfig());
    return cfg;
  });
}

export function getSrms(nodes: Node[]): SrmConfig[] {
  return nodes.filter(node => node instanceof SrmNode)
    .map(a => <SrmNode>a)
    .map(srm => srm.getConfig());
}

export function getMonitorBoards(nodes: Node[]): MonitorBoardConfig[] {
  return nodes.filter(node => node instanceof MonitorBoardNode)
    .map<MonitorBoardNode>(a => <MonitorBoardNode>a)
    .map(board => board.getConfig());
}

export function getRgvs(nodes: Node[]): RgvConfig[] {
  return nodes.filter(node => node instanceof RgvNode)
    .map<RgvNode>(a => <RgvNode>a)
    .map(board => board.getConfig());
}

export function loadScenario(graph: Graph, cfg: ScenarioConfig) {
  graph.clearCells();
  _loadPiplines(graph, cfg.Lines);
  _loadSrms(graph, cfg.Srms);
  _loadMonitorBoards(graph, cfg.Boards);
  _loadRgvs(graph, cfg.Rgvs);
}

function _loadPiplines(graph: Graph, lines: PiplineConifg[]) {
  lines.forEach(line => {
    const meta = PiplineNode.getMeta(line);
    const lineNode = graph.addNode(meta);
    line.Sites.forEach(site => {
      const siteNode = graph.addNode(SiteNode.getMeta(site));
      if (siteNode instanceof SiteNode) {
        siteNode.update(site);
      }
      lineNode.addChild(siteNode);
    });
  });
}

function _loadSrms(graph: Graph, items: SrmConfig[]) {
  items.forEach(cfg => {
    const meta = SrmNode.getMeta(cfg);
    const node = graph.addNode(meta);
    if (node instanceof SrmNode) {
      node.update(cfg);
    }
  });
}

function _loadMonitorBoards(graph: Graph, items: MonitorBoardConfig[]) {
  items.forEach(cfg => {
    const meta = MonitorBoardNode.getMeta(cfg);
    const node = graph.addNode(meta);
    if (node instanceof MonitorBoardNode) {
      node.update(cfg);
    }
  });
}

function _loadRgvs(graph: Graph, items: RgvConfig[]) {
  items.forEach(cfg => {
    const meta = RgvNode.getMeta(cfg);
    const node = graph.addNode(meta);
    if (node instanceof RgvNode) {
      node.update(cfg);
    }
  });
}

